package com.ibix.chj.autohome;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import com.ibix.chj.model.CarBrand;
import com.ibix.chj.model.CarListByCharacter;
import com.ibix.chj.model.CarModel;
import com.ibix.chj.model.CarSeries;

import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Selectable;

public class AutoHomePageProcessor implements PageProcessor
{
	private String[] chars;
	
	public AutoHomePageProcessor(String[] chars) {
		if (chars == null || chars.length == 0) {
			this.chars = new String[26];
			char a = 'A';
			for(int i=0;i<26;i++) {
				this.chars[i] = String.valueOf((char)(a + i)).toUpperCase();
			}
		} else {
			for (int i = 0; i < chars.length; i++) {
				chars[i] = chars[i].toUpperCase();
			}
			this.chars = chars;
		}
	}
	
	private boolean contains(String character)
	{
		if (chars == null)
			return false;
		
		for (int i = 0; i < chars.length; i++) {
			if (character.trim().equals(chars[i])) {
				return true;
			}
		}
		return false;
	}
	
	
	private Site site = Site.me().setRetryTimes(5).setSleepTime(200).setTimeOut(30000);
	// 创建一个map，存储所有数据
	private ConcurrentHashMap<String, CarListByCharacter> dataMap = new ConcurrentHashMap<String, CarListByCharacter>();
	
	private ConcurrentHashMap<String, CarBrand> brandMap = new ConcurrentHashMap<String, CarBrand>();
	
	private ConcurrentHashMap<String, CarSeries> seriesMap = new ConcurrentHashMap<String, CarSeries>();
	
	private ConcurrentHashMap<String, Boolean> sellMap = new ConcurrentHashMap<String, Boolean>();
	
	public void process(Page page) {
		String url = page.getUrl().toString().trim();
		
		if (url.equals("http://car.autohome.com.cn/AsLeftMenu/As_LeftListNew.ashx?typeId=1&brandId=0&fctId=0&seriesId=0"))
		{
			parseFirstPageData(page);
		}
		else if (url.startsWith("http://car.autohome.com.cn/price/brand")){
			long id = 0;
			// "http://car.autohome.com.cn/price/brand-x.html"
			String idStr = url.replaceAll("http://car.autohome.com.cn/price/brand-", "").replace(".html", "");
			try {
				id = Long.parseLong(idStr);
			} catch (NumberFormatException e) {
			}
			
			if (brandMap.containsKey(url))
			{
				CarBrand cb = brandMap.get(url);
				cb.setId(id);
				parseCarBrandData(page, cb);
			}
		}
		else if (url.startsWith("http://car.autohome.com.cn/price/series"))
		{
			long id = 0;
			// "http://car.autohome.com.cn/price/brand-x.html"
			String idStr = url.replaceAll("http://car.autohome.com.cn/price/series-", "").replace(".html", "");
			try {
				id = Long.parseLong(idStr);
			} catch (NumberFormatException e) {
			}
			
			if (getSeriesMap().containsKey(url))
			{
				CarSeries cs = getSeriesMap().get(url);
				cs.setId(id);
				boolean beingSold = true;
				String[] splitsUrl = url.split("#");
				
				String shortUrl = splitsUrl[0];
				if (getIsSellMap().containsKey(shortUrl)) {
					beingSold = false; //getIsSellMap().get(shortUrl);
				}
				System.out.println(">>>>>>>>>>>>>>>>>>>>>>>getIsSellMap().contains(url):" + getIsSellMap().containsKey(shortUrl));
				parseCarSeriesData(page, cs, beingSold);
			}
		}
	}

	private void parseCarSeriesData(Page page, CarSeries cs, boolean beingSold) {
		System.out.println("#############抓取车系品牌数据:" + cs.getName() + "#############" + cs.getLink());
		
		if (cs.getName().contains("停售")) {
			beingSold = false;
		}
		
		Selectable mainContent = page.getHtml().xpath("//div[@class='tab tab02 brandtab-cont']");
		parseMoreLinks(page, mainContent, cs, beingSold);
		
		parsePageLinks(page, mainContent, cs, beingSold);
		
		parseCarModelsData(page, mainContent, cs, beingSold);
	}
	
	private void parseCarModelsData(Page page, Selectable mainContent, CarSeries cs, boolean beingSold) {
		String secondaryCategory = page.getHtml().xpath("/html/body/div[2]/div[1]/div[2]/div[7]/div/div[2]/div/div[2]/div[2]/div[1]/ul/li[1]/span").regex(">.*<").replace(">", "").replace("<","").toString();
		cs.setSecondaryCategory(secondaryCategory);
		
		List<Selectable> uiList = mainContent.xpath("//div[@class='intervalcont border-b-no']/div").nodes();
		for (int i=0;i<uiList.size();i++)
		{
			List<Selectable> uiItem = uiList.get(i).$("ul").$("li").nodes();
			for (int itemIndex=0;itemIndex<uiItem.size();itemIndex++)
			{
				String name = uiItem.get(itemIndex).xpath("//div[@class='interval01-list-cars-infor']/p/a").regex(">.*</a>").replace("</a>", "").replace(">", "").toString().trim();
				
				String idString = uiItem.get(itemIndex).xpath("//div[@class='interval01-list-cars-infor']").$("p", "id").replace("p", "").toString();
				
				long id = 0;
				try{
					id = Long.parseLong(idString);
				} catch (NumberFormatException e) {
					
				}
				
				Selectable guidePriceSelectable = uiItem.get(itemIndex).xpath("//div[@class='interval01-list-guidance']/div");
				
				Selectable result = guidePriceSelectable.regex("</a>.*</div>");
				String guidePrice = "0.0万";
				if (result == null || result.toString() == null)
				{
					guidePrice = guidePriceSelectable.replace("<div>", "").replace("</div>", "").toString().trim();
				} 
				else
				{
					guidePrice = result.replace("</a>", "").replace("</div>", "").toString().trim();
				}
				
				// <span class="guidance-price">12.38万</span>
				guidePrice = guidePrice.replace("<span class=\"guidance-price\">", "").replace("</span>", "");
				
				// System.out.println("获取车型:[" + name + "] 指导价:[" + guidePrice + "]");
				
				CarModel cm = new CarModel();
				cm.setId(id);
				cm.setName(name);
				cm.setGuidePrice(guidePrice);
				if (cs.getName().contains("停售")) {
					cm.setBeingSold(false);
				} 
				else {
					cm.setBeingSold(beingSold);
				}
				cs.getModels().add(cm);
			}
			System.out.println("-----------------共获取车型" + cs.getModels().size() + "款--------------------------------");
		}
	}

	
	private void parsePageLinks(Page page, Selectable main, CarSeries cs, boolean beingSold) {
		Selectable morePages = main.xpath("//div[@class='page']");
		// 判断有没有分页,如果有分页，就把分页数据写进去
		if (morePages != null && morePages.toString() != null)
		{
			List<Selectable> pageList = morePages.$("a").nodes();
			for (int i=0;i<pageList.size();i++)
			{
				if (i == 0) // 上一页
					continue;
				if (i == pageList.size() - 1) // 下一页
					continue;
				
				String link = pageList.get(i).$("a", "href").toString();
				if (link == null)
				{
					continue;
				}
				if (cs.getLink().equals(link))
				{
					continue;
				}
				if (getSeriesMap().contains(link))
				{
					continue;
				}
				
				System.out.println("@@@增加抓取路径：" + link + "  原始路径:" + cs.getLink());
				
				if (!beingSold) {
					String[] splitLink = link.split("#");
					String shortLink = splitLink[0];
					getIsSellMap().put(shortLink, !beingSold);
				}
				
				// 记录到map
				getSeriesMap().put(link, cs);
				
				// 增加要请求队列
				page.addTargetRequest(link);
			}
		}		
	}

	// 解析 在售，即将销售，停售等几个链接
	private void parseMoreLinks(Page page, Selectable main, CarSeries cs, boolean csBeingSold)
	{
		// 遍历一下在售或者停售，以及即将销售的标签，把链接加入进来
		List<Selectable> moreLinks = main.xpath("//div[@class='tab-nav border-t-no']/ul/li").nodes();
//		System.out.println("moreLinks:" + moreLinks);
		for (int i=0;i<moreLinks.size();i++)
		{
			String link = moreLinks.get(i).$("a", "href").toString();
			
			if (link == null)
			{
				continue;
			}
			if (cs.getLink().contains(link))
			{
				continue;
			}
			if (getSeriesMap().contains(link))
			{
				continue;
			}
			
			String name = moreLinks.get(i).$("a", "title").toString();
			boolean beingSold = name == null ? true : !name.startsWith("停售");
			
			System.out.println("@@@增加抓取路径：" + link + "  原始路径:" + cs.getLink());
			
			
			if (!csBeingSold) {
				String[] splitLink = link.split("#");
				String shortLink = splitLink[0];
				getIsSellMap().put(shortLink, !csBeingSold);
			} else 
			
			if (!beingSold) {
				String[] splitLink = link.split("#");
				String shortLink = splitLink[0];
				getIsSellMap().put(shortLink, !beingSold);
			}
			
			// 记录到map
			getSeriesMap().put(link, cs);
			
			// 增加要请求队列
			page.addTargetRequest(link);
		}
	}

	private void parseCarBrandData(Page page, CarBrand cb) {
		System.out.println("=============抓取到车辆品牌数据:" + cb.getName() + "=============");
		
		Selectable carSeriesSelectable = page.getHtml().xpath("//div[@class='uibox']");
		
		String icon = carSeriesSelectable.xpath("//div[@class='carbradn-pic']").$("img","src").toString();
		System.out.println("icon:" + icon);
		cb.setIcon(icon);
		
		List<Selectable> uiList = carSeriesSelectable.xpath("//dl[@class='list-dl']").nodes();
		for (int i=0;i<uiList.size();i++)
		{
			Selectable uiItem = uiList.get(i);
			String type = uiItem.$("dt").$("a").regex(">.*<").replace(">", "").replace("<", "").toString();
			System.out.println("<<<<<<大分类:" + type);
			List<Selectable> categoryList = uiItem.$("dd").xpath("//div[@class='list-dl-name']").nodes();
			List<Selectable> typeList = uiItem.$("dd").xpath("//div[@class='list-dl-text']").nodes();
			for (int typeIndex=0;typeIndex<typeList.size();typeIndex ++)
			{
				List<Selectable> seriesList = typeList.get(typeIndex).$("a").nodes();
				String categoryString = categoryList.get(typeIndex).regex(">.*</div>").replace("</div>", "").replace(">", "").replace("：", "").toString().trim();
				System.out.println("分类::::::::::::::::: " + categoryString);
				for (int seriesIndex=0;seriesIndex<seriesList.size();seriesIndex ++)
				{
		
					String seriesName = seriesList.get(seriesIndex).$("a", "title").toString();
					String seriesLink = seriesList.get(seriesIndex).$("a", "href").toString();
					System.out.println("抓取车系:" + seriesName + "  url:" + seriesLink);
					
					// 保存车系数据
					CarSeries cs = new CarSeries();
					cs.setName(seriesName);
					cs.setLink(seriesLink);
					cs.setType(type);
					cs.setCategory(categoryString);
					cs.setModels(new ArrayList<CarModel>());
					cb.getSeries().add(cs);
					
					if (cs.getName().contains("停售")) {
						String[] splitsLink = seriesLink.split("#");
						String shortLink = splitsLink[0];
						getIsSellMap().put(shortLink, false);
					}
					
					// 把车系保存到map里，这样之后方便处理
					getSeriesMap().put(seriesLink, cs);
					
					// 增加请求队列
					page.addTargetRequest(seriesLink);
				}
			}
		}
		
	}

	private void parseFirstPageData(Page page) {
		List<Selectable> lettersList= page.getHtml().xpath("//div[@class='cartree-letter']").nodes();
		List<Selectable> brandsList = page.getHtml().$("ul").nodes();
		
		System.out.println("读取到" + lettersList.size() + "个字符,  以及" + brandsList.size() + "个列表");
		
		for (int i=0;i<lettersList.size();i++)
		{
			
			
			Selectable letterSelectable = lettersList.get(i);
			String letter = letterSelectable.regex(">.*[A-Z].*<").replace(">", "").replace("<", "").toString().trim();
			
			if (!contains(letter))
				continue;
			
			System.out.println("==============字母" + letter + "==============");
			
			
			
			// -------------  保存字母的数据 -----------------
			CarListByCharacter clbc = new CarListByCharacter();
			clbc.setBrands(new ArrayList<CarBrand>());
			clbc.setCharacter(letter);
			getDataMap().put(letter, clbc);
			// -----------------------------------------
			
			List<Selectable> brandsListOfThisLetter = brandsList.get(i).$("li").nodes();
			for (int j=0;j<brandsListOfThisLetter.size();j++)
			{
				Selectable brandSelectable = brandsListOfThisLetter.get(j);
				String name = brandSelectable.regex("</i>.*<em>").replace("</i>", "").replace("<em>", "").toString().trim();
				
				String link = brandSelectable.$("a", "href").toString();
				System.out.println("抓取name:" + name + " 链接:" + link);
				
				// ------------ 保存品牌数据 -----------------
				CarBrand cb = new CarBrand();
				cb.setName(name);
				cb.setLink(link);
				cb.setSeries(new ArrayList<CarSeries>());
				clbc.getBrands().add(cb);
				// --------------------------------------
				
				// 把品牌数据保存到一个map，方便查询
				brandMap.put(link, cb);
				
				page.addTargetRequest(link);
			}
		}
		
		page.putField("data", getDataMap());
	}

	public Site getSite() {
		return site;
	}

	public ConcurrentHashMap<String, CarSeries> getSeriesMap() {
		return seriesMap;
	}

	public ConcurrentHashMap<String, CarListByCharacter> getDataMap() {
		return dataMap;
	}
	
	public ConcurrentHashMap<String, Boolean> getIsSellMap()
	{
		return sellMap;
	}
}
